﻿using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Factories;
using FarseerGames.GettingStarted.DrawingSystem;
using FarseerGames.GettingStarted.ScreenSystem;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Netpong.Networking;
using XNALibrary.ZCAMERA;
using System;
using XNALibrary;
using NetPong.Networking;

namespace NetPong
{
    public class Paddle : ITransmittable, IControllable, IWatchable
    {
        public Body body;
        public PlayerIndex playerIndex;
        public Geom geom;
        public int ObjectId { get { return objectId; } }
        private int objectId;

        int height = 144;
        int width = 32;
        Texture2D paddleTexture;
        Vector2 paddleOrigin;

        ScreenManager screenManager;

        public Paddle(Vector2 position)
        {
            //fix this later
        }

        public Paddle(Vector2 position, PhysicsSimulator physicsSimulator, ScreenManager ScreenManager, NetworkManager nm)
        {
            objectId = nm.CreateNetworkObj(this);
            body = new Body();
            body.Mass = 1f;
            body.MomentOfInertia = body.Mass * (this.width * this.width + this.height * this.height) / 12;
            body.Position = position;
            
            physicsSimulator.Add(body);
            

            this.geom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, body, width, height);

            //this reference will be removed because the paddle will be rendered using its model
            screenManager = ScreenManager;
            paddleTexture = DrawingHelper.CreateRectangleTexture(screenManager.GraphicsDevice, this.width, this.height, Color.Cyan, Color.Silver);
            paddleOrigin = new Vector2(paddleTexture.Width / 2f, paddleTexture.Height / 2f);
        }

        #region ITransmittable Members

        public PacketWriter WriteToNetwork()
        {
            PacketWriter packetWriter = new PacketWriter();
            packetWriter.Write(objectId);
            packetWriter.Write(body.Position);
            packetWriter.Write((double)body.Rotation);

            return packetWriter;
        }

        public void UpdateFromNetwork(PacketReader packetReader)
        {
            Vector2 force = packetReader.ReadVector2();

            if (body.LinearVelocity.Length() > 1000)
            {
                body.LinearVelocity.Normalize();
                body.LinearVelocity = body.LinearVelocity * 1000;
            }

            if (force == Vector2.Zero) { body.LinearVelocity = Vector2.Zero; }
            else body.ApplyForce(force);

            float torque = (float)packetReader.ReadDouble();
            body.ApplyTorque(torque);

            if (body.AngularVelocity > 15)
            {
                body.AngularVelocity = 15;
            }
            if (body.AngularVelocity < -15)
            {
                body.AngularVelocity = -15;
            }

            if (torque == 0) { body.AngularVelocity = 0; }
        }

        #endregion

        #region IRenderable Members

        public virtual void Render(GameTime gt)
        {
            //TODO: fix this with delegate
            RenderDefault(gt);
        }

        public virtual void RenderDefault(GameTime gt)
        {
            screenManager.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            screenManager.SpriteBatch.Draw(paddleTexture, this.geom.Position, null, Color.White,
                                           this.geom.Rotation, paddleOrigin, 1, SpriteEffects.None, 0);
            screenManager.SpriteBatch.End();
        }

        #endregion

        #region Handle Input
        public void ReadInput()
        {
            GamePadState gamePad = GamePad.GetState(playerIndex);
            if (gamePad.IsConnected)
            {
                HandleGamePadInput(gamePad);
            }
            else
            {
                HandleKeyboardInput();
            }
        }

        public void HandleGamePadInput(GamePadState gps)
        {
            Vector2 force = 500 * gps.ThumbSticks.Left;
            force.Y = -force.Y;
            body.ApplyForce(force);

            float rotation = -1000 * gps.Triggers.Left;
            rotation += 1000 * gps.Triggers.Right;

            body.ApplyTorque(rotation);
        }

        public void HandleKeyboardInput(){
            const float forceAmount = 5000;
            Vector2 force = Vector2.Zero;

            KeyboardState keyState = Keyboard.GetState(playerIndex); ;

            if (keyState.IsKeyDown(Keys.A)) { force += new Vector2(-forceAmount, 0); }
            if (keyState.IsKeyDown(Keys.S)) { force += new Vector2(0, forceAmount); }
            if (keyState.IsKeyDown(Keys.D)) { force += new Vector2(forceAmount, 0); }
            if (keyState.IsKeyDown(Keys.W)) { force += new Vector2(0, -forceAmount); }

            body.ApplyForce(force);
            
            if (body.LinearVelocity.Length() > 1000)
                {
                    body.LinearVelocity.Normalize();
                    body.LinearVelocity = body.LinearVelocity * 1000;
                }
            if (force == Vector2.Zero) 
            { 
                body.LinearVelocity = Vector2.Zero; 
            }
           

            const float torqueAmount = 300000;
            float torque = 0;

            if (keyState.IsKeyDown(Keys.Left)) { torque -= 1.2f * torqueAmount; }
            if (keyState.IsKeyDown(Keys.Right)) { torque += 1.2f * torqueAmount; }

             body.ApplyTorque(torque);
          // if (networkSession.IsHost)
           // {
                if (body.AngularVelocity > 15)
                {
                    body.AngularVelocity = 15;
                }
                if (body.AngularVelocity < -15)
                {
                    body.AngularVelocity = -15;
                }
                if (torque == 0) { body.AngularVelocity = 0; }
          //  }
        }
        #endregion

        #region IWatchable Members

        public Vector3 GetPosition()
        {
            return new Vector3(body.Position.X,0,body.Position.Y);
        }

        public Vector3 GetDirection()
        {
            return new Vector3((float)Math.Cos(body.Rotation), 0f, (float)Math.Sin(body.Rotation));
        }

        public Vector3 GetUp()
        {
            return Vector3.Up;
        }

        #endregion
    }
}
